home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 1.iso / dist / fw_exmh.idb / usr / freeware / lib / exmh-2.5 / pgpExec.tcl.z / pgpExec.tcl
Text File  |  2002-07-08  |  25KB  |  797 lines

  1. # pgpInterface.tcl -- 
  2. # created by monnier@didec26.epfl.ch on Mon Dec 12 17:34:38 1994
  3.  
  4.  
  5. # $Log: pgpExec.tcl,v $
  6. # Revision 1.15  2000/09/21 15:06:44  valdis
  7. # Catch PGP stderr so 'Get key' and 'Generate Key' work...
  8. #
  9. # Revision 1.14  2000/06/16 18:16:26  valdis
  10. # Various PGP fixes...
  11. #
  12. # Revision 1.13  2000/06/15 17:03:11  valdis
  13. # Add X-Mailer: change, fix PGP Comment: line...
  14. #
  15. # Revision 1.12  2000/04/18 18:38:33  valdis
  16. # Fix quote character to use ascii rather than iso8859-ish one
  17. #
  18. # Revision 1.11  1999/09/27 23:18:45  kchrist
  19. # More PGP changes. Consolidated passphrase entry to sedit field or
  20. # pgpExec routine. Made the pgp-sedit field aware of pgp(keeppass)
  21. # and pgp(echopass). Moved pgp(keeppass), pgp(echopass) and
  22. # pgp(grabfocus) to PGP General Interface. Fixed a minor bug left
  23. # over from my previous GUI changes. Made pgp-sedit field appear and
  24. # disappear based on its enable preference setting.
  25. #
  26. # Revision 1.10  1999/09/22 16:36:44  kchrist
  27. # Changes made to support a different structure under the PGP Crypt... button.
  28. # Instead of an ON/OFF pgp($v,sign) variable now we use it to specify
  29. # the form of the signature (none, standard, detached, clear, or w/encrypt).
  30. # Code changed in several places to support this new variable definition.
  31. #
  32. # Updated Sedit.html to include a description of the new interface.
  33. #
  34. # Revision 1.9  1999/08/22 18:57:36  bmah
  35. # Sanitize PGP debugging entries before writing via Exmh_Debug.
  36. #
  37. # Revision 1.8  1999/08/13 00:39:05  bmah
  38. # Fix a number of key/passphrase management problems:  pgpsedit now
  39. # manages PGP versions, keys, and passphrases on a per-window
  40. # basis.  Decryption now works when no passphrases are cached.
  41. # One timeout parameter controls passphrases for all PGP
  42. # versions.  seditpgp UI slightly modified.
  43. #
  44. # Revision 1.7  1999/08/04 22:43:39  cwg
  45. # Got passphrase timeout to work yet again
  46. #
  47. # Revision 1.6  1999/08/04 16:30:17  cwg
  48. # Don't prompt for a passphrase when we shouldn't.
  49. #
  50. # Revision 1.5  1999/08/03 04:05:54  bmah
  51. # Merge support for PGP2/PGP5/GPG from multipgp branch.
  52. #
  53. # Revision 1.4.2.1  1999/06/14 20:05:15  gruber
  54. # updated multipgp interface
  55. #
  56. # Revision 1.4  1999/06/10 16:59:18  cwg
  57. # Re-enabled the timeout of PGP passwords
  58. #
  59. # Revision 1.3  1999/05/04 06:35:38  cwg
  60. # Fixed crash when aborting out of PGP Password window
  61. #
  62. # Revision 1.2  1999/04/10 04:20:08  cwg
  63. # Do the right thing if pgp(seditpgp) is not enabled.
  64. #
  65. # Revision 1.1  1998/05/05 17:55:37  welch
  66. # Initial revision
  67. #
  68. # Revision 1.1  1998/05/05 17:42:59  welch
  69. # Initial revision
  70. #
  71. # Revision 1.11  1998/01/22  00:45:06  bwelch
  72. #     Hack to use aixterm for PGP.
  73. #
  74. # Revision 1.10  1997/12/22  20:52:00  bwelch
  75. # file delete
  76. #
  77. # Revision 1.9  1997/07/25  17:13:23  bwelch
  78. # Fixed pattern match to handle PGP 5.0 date format.
  79. #
  80. # Revision 1.8  1997/07/12  23:05:12  bwelch
  81. #     Fixed PGP key extraction from the web servers.
  82. #     Fixed handling of failed signatures so you still see the message.
  83. #
  84. # Revision 1.7  1997/06/03  18:29:55  bwelch
  85. # Added PGP grab-focus and use-expecttk options.
  86. # Removed +keepbinary=off flag from PGP uses.
  87. # PGP bin directory is added to the front of PATH, if necessary
  88. #
  89. # Revision 1.6  1997/01/25  05:29:23  bwelch
  90. #     Tweaked PgpExec_KeyList that returns a list of keys.
  91. #     Tweaked patterns on PGP output.
  92. #     Added Pgp_ShortenOutput
  93. #
  94. # Revision 1.5  1996/12/21  00:57:12  bwelch
  95. # Log errors from PGP key extraction
  96. #
  97. # Revision 1.4  1996/12/01  20:13:59  bwelch
  98. # Added Pgp_InterpretOutput
  99. # Added timeouts on password caching.
  100. #
  101. # Revision 1.3  1996/03/22  18:42:54  bwelch
  102. # Added Mh_Rename
  103. # .
  104. #
  105. # Revision 1.2  1995/05/24  05:58:04  bwelch
  106. # Updates from Stefan
  107. #
  108. # Revision 1.1  1995/05/19  17:36:16  bwelch
  109. # Initial revision
  110. #
  111. # Revision 1.2  1995/03/22  19:14:21  welch
  112. # More new code from Stefan
  113. #
  114. # Revision 1.1  1994/12/30  21:49:00  welch
  115. # Initial revision
  116. #
  117. # Revision 1.1  1994/12/17  20:19:16  monnier
  118. # Initial revision
  119. #
  120.  
  121. # execs pgp with the usual flags
  122. proc Pgp_Exec { v exectype arglist outvar {privatekey {}} {interactive 0} } {
  123.     global pgp env
  124.     upvar $outvar output
  125.  
  126.     Exmh_Debug "Pgp_Exec $v $exectype $arglist $outvar $privatekey $interactive"
  127.  
  128.     if {![set pgp($v,enabled)]} {
  129.     error "<[set pgp($v,fullName)]> isn't enabled"
  130.     }
  131.  
  132.     set output {}
  133.     if {![set pgp(keeppass)]} {
  134.     Pgp_ClearPassword $v
  135.     }
  136.     if {$interactive || !([set pgp(keeppass)] || ($privatekey == {}))} {
  137.         Exmh_Debug "<Pgp_Exec> Pgp_Exec_Interactive $v $exectype $arglist output"
  138.     return [Pgp_Exec_Interactive $v $exectype $arglist output]
  139.     } else {
  140.     if {$privatekey == {}} {
  141.             Exmh_Debug "<PGP Pgp_Exec> Pgp_Exec_Batch $v $exectype $arglist output"
  142.         return [Pgp_Exec_Batch $v $exectype $arglist output]
  143.     } else {
  144.         Exmh_Debug v=$v
  145.  
  146.         set keyid [lindex $privatekey 0]
  147.         Exmh_Debug keyid=$keyid
  148.         # Check for passphrase. Pgp_GetPass is cache and expire aware!
  149.         set p [Pgp_GetPass $v $privatekey]
  150.         #Exmh_Debug "<Pgp_Exec> got passwd >$p<"
  151.  
  152.         if {[string length $p] == 0} {
  153.         return 0
  154.         }
  155.             Exmh_Debug "<Pgp_Exec> Pgp_Exec_Batch $v $exectype $arglist output \(password\)"
  156.         return [Pgp_Exec_Batch $v $exectype $arglist output $p]
  157.     }
  158.     }
  159. }
  160.  
  161. # batch mode
  162. proc Pgp_Exec_Batch { v exectype arglist outvar {password {}} } {
  163.     global pgp exmh errorCode
  164.     upvar $outvar output
  165.  
  166.     Exmh_Debug "Pgp_Exec_Batch $v $exectype $arglist $outvar \(password\)"
  167.  
  168.     set tclcmd [concat exec [set pgp($v,executable,$exectype)] \
  169.                               [subst [set pgp($v,flags_batch)]] $arglist]
  170.  
  171.     Exmh_Debug "<Pgp_Exec_Batch> $tclcmd"
  172.  
  173.     # Set file descriptor for passphrase on stdin
  174.     if {$password == {}} {
  175.         Pgp_${v}_PassFdUnset
  176.     } else {
  177.         lappend tclcmd << $password
  178.         Pgp_${v}_PassFdSet
  179.     }
  180.  
  181.     set result [catch {eval $tclcmd |& cat} output]
  182.     Exmh_Debug "<Pgp_Exec_Batch>: Exit status: $result $errorCode"
  183.  
  184.     # Unset file descriptor for passphrase
  185.     Pgp_${v}_PassFdUnset
  186.  
  187.     regsub -all "\x07" $output "" output
  188.     return $result
  189. }
  190.  
  191. # interactive mode
  192. proc Pgp_Exec_Interactive { v exectype arglist outvar } {
  193.     global tcl_platform pgp
  194.     upvar $outvar output
  195.  
  196.     Exmh_Debug "Pgp_Exec_Interactive $v $exectype $arglist $outvar"
  197.  
  198.     set pgpcmd [set pgp($v,executable,$exectype)]
  199.     set args [concat [subst [set pgp($v,flags_interactive)]] $arglist]
  200.  
  201.     # Be sure, that passphrase isn't read from stdin
  202.     Pgp_${v}_PassFdUnset
  203.  
  204.     # Build shellcommand
  205.     set shcmd "
  206.         $pgpcmd \"[join [Pgp_Misc_Map x {
  207.         regsub {([$\"\`])} $x {\\1} x
  208.         set dummy $x
  209.         } $args] {" "}]\";
  210.     echo
  211.     echo press Return...;
  212.         read dummy"
  213.  
  214.     set logfile [Mime_TempFile "xterm"]
  215.     if { ( $tcl_platform(os) == "AIX" ) && [ file executable "/usr/bin/X11/aixterm" ] } {
  216.         set xterm "aixterm"
  217.     } else {
  218.         set xterm "xterm"
  219.     }
  220.  
  221.     # Hint: XFree86 xterm does not support output logging (Markus)
  222.     # -l and -lf not supported
  223.  
  224.     set tclcmd {exec $xterm -l -lf $logfile -title [set pgp($v,fullName)] -e sh -c $shcmd}
  225.     Exmh_Debug "<Pgp_Exec_Interactive> $tclcmd"
  226.     set result [catch $tclcmd]
  227.     if [catch {open $logfile r} log] {
  228.     set output {}
  229.     } else {
  230.     set output [read $log]
  231.     close $log
  232.     }
  233.  
  234.     eval [set pgp($v,cmd_cleanOutput)]
  235.  
  236.     return $result
  237. }
  238.  
  239. proc Pgp_Exec_CheckPassword { v password key } {
  240.     global pgp
  241.  
  242.     Exmh_Debug "Pgp_Exec_CheckPassword $v \(password\) $key"
  243.  
  244.     set in [Mime_TempFile "pwdin"]
  245.     set out [Mime_TempFile "pwdout"]
  246.     set filio [open $in w 0600]
  247.     puts $filio "salut"
  248.     close $filio
  249.     set keyid [lindex $key 0]
  250.  
  251.     Pgp_Exec_Batch $v sign [subst [set pgp($v,args_signClear)]] err $password
  252.  
  253.     File_Delete $in
  254.  
  255.     # pgp thinks he knows better how to name files !
  256.     if {![file exists $out] && [file exists "$out.asc"]} {
  257.     Mh_Rename "$out.asc" $out
  258.     }
  259.     if {![file exists $out]} {
  260.         if [regexp [set pgp($v,pat_checkError)] $err x match] {
  261.             Exmh_Status ?${match}?
  262.         }
  263.         Exmh_Debug "<Pgp_Exec_CheckPassword> $err"
  264.     return 0
  265.     } else {
  266.     File_Delete $out
  267.     return 1
  268.     }
  269. }
  270.  
  271. # returns a list of keys. Each "key" is a list whose first four elements are
  272. # keyid algo subkeyid algo
  273. # and the next ones are the corresponding userids
  274. # {keyid algo subkeyid algo userid userid userid ...}
  275. proc Pgp_Exec_KeyList { v pattern keyringtype } {
  276.     global pgp
  277.  
  278.     Exmh_Debug "Pgp_Exec_Keylist $v $pattern $keyringtype"
  279.  
  280.     set pattern [string trimleft $pattern "<>|2"]
  281.     set arglist [subst [set pgp($v,args_list$keyringtype)]]
  282.     ldelete arglist {}
  283.  
  284.     Pgp_Exec_Batch $v key $arglist keylist
  285.  
  286.     Exmh_Debug "<Pgp_Exec_Keylist>: $keylist"
  287.  
  288.     # drop revoked and noninteresting keys
  289.     regsub -all [set pgp($v,pat_dropKeys)] $keylist {} keylist
  290.  
  291.     # Form a list of keys
  292.     regsub -all [set pgp($v,pat_splitKeys)] $keylist \x81 keylist
  293.     set keylist [split $keylist \x81]
  294.  
  295.     Exmh_Debug "<Pgp_Exec_Keylist>: Splitted keylist: $keylist"
  296.  
  297.     # Match out interesting keys
  298.     set keypattern [set pgp($v,pat_key$keyringtype)]
  299.  
  300.     # subkeyparsing
  301.     if [info exists pgp($v,pat_key${keyringtype}_sub)] {
  302.         set subkeypattern [set pgp($v,pat_key${keyringtype}_sub)]
  303.     }
  304.  
  305.     # uid parsing
  306.     set uidpattern [set pgp($v,pat_uid)]
  307.  
  308.     # grep keys
  309.     set AllowedToFollow 0
  310.     set keys {}
  311.     foreach line $keylist {
  312.         catch {unset userid}
  313.         catch {unset keyid}
  314.         set goodline 0
  315.         #
  316.         if {[eval [set pgp($v,cmd_keyMatch)]]} {
  317.             if {[info exists userids] && [info exists keyids]} {
  318.                 if {[llength $keyids] < 4} {
  319.                     lappend keyids {} {}
  320.                 }
  321.                 lappend keys [concat $keyids $userids]
  322.                 unset keyids
  323.                 unset userids
  324.             }
  325.             lappend keyids "0x$keyid" $algo
  326.             catch {lappend userids $userid}
  327.             set AllowedToFollow 1
  328.             set goodline 1
  329.         }    
  330.         if [info exists subkeypattern] {
  331.             if {[eval [set pgp($v,cmd_keyMatch_sub)]] && $AllowedToFollow} {
  332.                 lappend keyids "0x$keyid" $algo
  333.                 set goodline 1
  334.             }
  335.         }
  336.         if {[eval [set pgp($v,cmd_uidMatch)]] && $AllowedToFollow} {
  337.             lappend userids $userid
  338.             set goodline 1
  339.         }
  340.         if {!$goodline} {
  341.             set AllowedToFollow 0
  342.         }
  343.     }
  344.     if {[info exists userids] && [info exists keyids]} {
  345.         if {[llength $keyids] < 4} {
  346.             lappend keyids {} {}
  347.         }
  348.         lappend keys [concat $keyids $userids]
  349.     }
  350.  
  351.     # keys is of the format { {keyid algo subkeyid algo userid userid} {} {}...}
  352.     return $keys
  353. }
  354.  
  355. # parse config file
  356. # this is only needed to set pgp($v,myname)
  357. proc Pgp_Exec_ParseConfigTxt { v file } {
  358.     global pgp
  359.  
  360.     Exmh_Debug "Pgp_Exec_ParseConfigTxt $file"
  361.  
  362.     if [catch {open $file r} in] {
  363.     return
  364.     }
  365.     for {set len [gets $in line]} {$len >= 0} {set len [gets $in line]} {
  366.     if [regexp -nocase "^\[ \t]*(\[a-z]+)\[ \t]*=(\[^#]*)" $line {} option value] {
  367.         set pgp($v,config,[string tolower $option]) [string trim $value " \t\""]
  368.     }
  369.     }
  370.     close $in
  371. }
  372.  
  373.  
  374. ###############
  375. # Encrypt/Sign
  376.  
  377. proc Pgp_Exec_Encrypt { v in out tokeys } {
  378.     global pgp
  379.  
  380.     Exmh_Debug "Pgp_Exec_Encrypt $v $in $out $tokeys"
  381.  
  382.     Pgp_Exec_Batch $v encrypt [subst [set pgp($v,args_encrypt)]] output
  383.     if {[Pgp_Exec_CheckSuccess $v $out $output "encrypted text"]} {
  384.         # pgp refuses to generate an encrypted message
  385.         # if a key was untrusted
  386.         # interactively proceed
  387.         Pgp_Exec_Interactive $v encrypt [subst [set pgp($v,args_encrypt)]] output
  388.     }
  389. }
  390.  
  391. proc Pgp_Exec_EncryptSign { v in out sigkey tokeys } {
  392.     global pgp
  393.  
  394.     Exmh_Debug "Pgp_Exec_EncryptSign $v $in $out $tokeys"
  395.  
  396.     set keyid [lindex $sigkey 0]
  397.     Pgp_Exec $v encrypt [subst [set pgp($v,args_encryptSign)]] output $sigkey
  398.     if {[Pgp_Exec_CheckSuccess $v $out $output "signed and encrypted text"]} {
  399.         # pgp refuses to generate an encrypted/signed message
  400.         # if a key was untrusted
  401.         # interactively proceed
  402.         Pgp_Exec $v encrypt [subst [set pgp($v,args_encryptSign)]] output $sigkey 1
  403.     }
  404. }
  405.  
  406. proc Pgp_Exec_Sign { v in out sigkey opt } {
  407.     global pgp
  408.  
  409.     Exmh_Debug "Pgp_Exec_Sign $v $in $out $sigkey $opt"
  410.  
  411.     set keyid [lindex $sigkey 0]
  412.     switch $opt {
  413.     standard {Pgp_Exec $v sign [subst [set pgp($v,args_signBinary)]] output $sigkey}
  414.     detached {Pgp_Exec $v sign [subst [set pgp($v,args_signDetached)]] output $sigkey}
  415.     clearsign {Pgp_Exec $v sign [subst [set pgp($v,args_signClear)]] output $sigkey}
  416.     default {set output "Pgp_Exec_Sign error. Unknown option."}
  417.     }
  418.     Pgp_Exec_CheckSuccess $v $out $output "signed text"
  419. }
  420.     
  421. # Look if pgp generated pgp code
  422. proc Pgp_Exec_CheckSuccess {v out output object} {
  423.     global pgp
  424.  
  425.     Exmh_Debug "Pgp_Exec_CheckSuccess $v $out $output $object"
  426.  
  427.     # pgp thinks he knows better how to name files !
  428.     if {![file exists $out] && [file exists "$out.asc"]} {
  429.     Mh_Rename "$out.asc" $out
  430.     }
  431.     if {![file exists $out]} {
  432.         # pgp5 refuses to generate ciphertext in batchmode if tokey is untrusted
  433.         if {[regexp [set pgp($v,pat_Untrusted)] $output]} {
  434.             return 1
  435.         } else {
  436.         error "[set pgp($v,fullName)] refused to generate the ${object}:\n$output"
  437.         }
  438.     } else {
  439.     return 0
  440.     }
  441. }    
  442.  
  443.  
  444. #################
  445. # Decrypt/Verify
  446.  
  447. # get the key to use for decryption
  448. proc Pgp_Exec_GetDecryptKey {v in recipients} {
  449.     global pgp
  450.  
  451.     Exmh_Debug "Pgp_Exec_GetDecryptKey $v $in $recipients"
  452.  
  453.     # If the user has time (this doesn't consume more than a half second)
  454.     # and has set preferences to run pgp twice,
  455.     # run pgp a first time to get out the decryption keyid
  456.     set runtwice 0
  457.     if {[info exists pgp($v,runtwice)] && [set pgp($v,runtwice)]} {
  458.         set runtwice 1
  459.     }
  460.     if {$runtwice} {
  461.       Exmh_Debug "<Pgp_Exec_GetDecryptKey> Pgp_Exec_GetDecryptKeyid $v $in"
  462.       set keyid [Pgp_Exec_GetDecryptKeyid $v $in]
  463.       if {$keyid == {}} {
  464.         return {}
  465.       } elseif {[string match $keyid SYM]} {
  466.         # SYMMETRIC ENCRYPTION
  467.         set key [list SYM {} {} {} "symmetrically encrypted message"]
  468.       } else {
  469.       # One of user's private keys?  If so, than use it.
  470.         foreach key [set pgp($v,privatekeys)] {
  471.           if {[regexp $keyid [lindex $key 0]]} {
  472.             return $key
  473.           } elseif {[regexp $keyid [lindex $key 2]]} {
  474.             return $key
  475.           }
  476.         }
  477.       }
  478.     } else {
  479.       set recipients [string tolower $recipients]
  480.       # Messages get encrypted with the subkey for dsa/elg
  481.       # I don't know if there are subkeyids in the recipients list if dsa/elg
  482.       # Lets search for mainkeys
  483.       set useablekeys [Pgp_Misc_Filter key \
  484.          {[string first [string tolower [string range [lindex $key 0] 2 end]] $recipients] >= 0} \
  485.          [set pgp($v,privatekeys)]]
  486.       # If no mainkeys were found, search for subkeys
  487.       if {[llength $useablekeys] == 0} {
  488.         set useablekeys [Pgp_Misc_Filter key \
  489.          {[string first [string tolower [string range [lindex $key 2] 2 end]] $recipients] >= 0} \
  490.          [set pgp($v,privatekeys)]]
  491.       }
  492.       set knownkeys [Pgp_Misc_Filter key \
  493.          {[info exists pgp($v,pass,[lindex $key 0])]} $useablekeys]
  494.  
  495.       if {[llength $knownkeys] > 0} {
  496.         set key [lindex $knownkeys 0]
  497.       } elseif {[llength $useablekeys] > 0} {
  498.         set key [lindex $useablekeys 0]
  499.       } else {
  500.         set key {}
  501.       }
  502.     }
  503.     return $key
  504. }
  505.  
  506. proc Pgp_Exec_GetDecryptKeyid {v in} {
  507.     global pgp
  508.  
  509.     Exmh_Debug "Pgp_Exec_GetDecryptKeyid $v $in"
  510.  
  511.     Pgp_Exec_Batch $v verify [subst [set pgp($v,args_getDecryptKeyid)]] output
  512.     if {[regexp [set pgp($v,pat_getDecryptKeyid)] $output {} keyid]} {
  513.     } elseif {[regexp [set pgp($v,pat_getDecryptSym)] $output]} {
  514.       set keyid SYM
  515.     } else {
  516.       Exmh_Debug "<Pgp_Exec_GetDecryptKeyid> No key matches"
  517.       return {}
  518.     }
  519.     Exmh_Debug "<Pgp_Exec_GetDecryptKeyid> keyid $keyid"
  520.     return $keyid
  521. }
  522.  
  523. proc Pgp_Exec_Decrypt { v in out outvar recipients } {
  524.     global pgp
  525.     upvar $outvar output
  526.  
  527.     Exmh_Debug "Pgp_Exec_Decrypt $v $in $out $outvar $recipients"
  528.  
  529.     set key [Pgp_Exec_GetDecryptKey $v $in $recipients]
  530.     Exmh_Debug "<Pgp_Exec_Decrypt> $key"
  531.     
  532.     Pgp_Exec $v verify [subst [set pgp($v,args_decrypt)]] output $key
  533. }
  534.  
  535. proc Pgp_Exec_Verify { v in outvar {out {}}} {
  536.     upvar $outvar output
  537.     global pgp
  538.  
  539.     Exmh_Debug "Pgp_Exec_Verify $v $in $outvar $out"
  540.  
  541.     if {$out == {}} {
  542.         Exmh_Debug "<Pgp_Exec_VerifyOnly>: Pgp_Exec_Verify $v $in $outvar $out"
  543.         Pgp_Exec $v verify [subst [set pgp($v,args_verifyOnly)]] output
  544.     } else {
  545.         Exmh_Debug "<Pgp_Exec_VerifyOut>: Pgp_Exec_Verify $v $in $outvar $out"
  546.         Pgp_Exec $v verify [subst [set pgp($v,args_verifyOut)]] output
  547.     }
  548. }
  549.  
  550. proc Pgp_Exec_VerifyDetached { v sig text outvar } {
  551.     upvar $outvar output
  552.     global pgp
  553.  
  554.     Exmh_Debug "Pgp_Exec_VerifyDetached $v $sig $text $outvar"
  555.  
  556.     Pgp_Exec $v verify [subst [set pgp($v,args_verifyDetached)]] output
  557. }
  558.  
  559. ##################
  560. # NOT WITH GNUPG
  561. #
  562. # This is called if expectk is enabled.  It seemed the best (easiest
  563. # for me) way to do it was to have this proc terminate when the
  564. # message is finished displaying just as Exec_Decrypt would do.
  565. # However, this is a problem for the the expectk script
  566. # (PgpDecryptExpect), which may need to communicate with exmh to ask
  567. # for passwords, etc.  
  568.  
  569. # My slow and inelegant solution was to tell exmh-bg all the necessary
  570. # information and let PgpDecryptExpect communicate with exmh-bg,
  571. # exiting when done.
  572. #
  573. proc Pgp_Exec_DecryptExpect { v infile outfile msgvar } {
  574.     global exmh exwin sedit pgp
  575.     upvar $msgvar msg
  576.  
  577.     # First update exmh-bg arrays.  I hope that pgp, getpass,
  578.     # and exwin will be enough.  For exwin seems we have
  579.     # to temporarily change the mtext error to avoid an error when
  580.     # the password window is closed and focus is returned to .msg.t
  581.  
  582.     send $exmh(bgInterp) [list array set pgp [array get pgp]]
  583.     send $exmh(bgInterp) [list array set getpass [array get getpass]]
  584.     send $exmh(bgInterp) [list array set sedit [array get sedit]]
  585.     send $exmh(bgInterp) [list array set exwin [array get exwin]]
  586.     send $exmh(bgInterp) [list set exwin(mtext) .]
  587.  
  588.     if [catch {exec $exmh(expectk) -f $exmh(library)/PgpDecryptExpect \
  589.                         $v $infile $outfile $exmh(bgInterp)} error] {
  590.         Exmh_Debug "<PGP Exec_DecryptExpect> error: $error"
  591.         Exmh_Status "Error executing expect process" warn
  592.     }
  593.  
  594.     set msg [lindex [send $exmh(bgInterp) {list $pgpmsg}] 0]
  595.     send $exmh(bgInterp) [list unset pgpmsg]
  596.  
  597.     # Now reload pass and exwin from exmh-bg
  598.     foreach index [send $exmh(bgInterp) [list array names pgp $v,pass,*]] {
  599.         set pgp($index) [send $exmh(bgInterp) [list set pgp($index)]]
  600.         send $exmh(bgInterp) [list unset pgp($index)]
  601.     }
  602.     # The following appears no longer to be necessary, but now I don't see
  603.     # how to change the position of the getpass window
  604.     #
  605.     #    set exwin(geometry,.getpass) \
  606.     #    [send $exmh(bgInterp) list {$exwin(geometry,.getpass)}]
  607. }
  608.  
  609. ####################
  610.  
  611. proc Pgp_Exec_ExtractKeys { v file outvar {interactive 1} } {
  612.     global env pgp
  613.     upvar $outvar output
  614.  
  615.     Exmh_Debug "Pgp_Exec_ExtractKeys $v $file $outvar $interactive"
  616.  
  617.     set output {}
  618.     if [Pgp_Exec $v key [subst [set pgp($v,args_importKey)]] output {} $interactive] {
  619.         Exmh_Status "Key extract failed"
  620.         Exmh_Debug "<Pgp_Exec_ExtractKeys> $output"
  621.         return 0
  622.     } else {
  623.         Exmh_Debug "<Pgp_Exec_ExtractKeys> $output"
  624.         return 1
  625.     }
  626. }
  627.  
  628. # Get the passphrase for keyinstance key. We also take care of setting
  629. # passphrase timeouts. Return a stored passphrase when possible.
  630. proc Pgp_GetPass { v key } {
  631.     global pgp
  632.  
  633.     Exmh_Debug "Pgp_GetPass $v $key"
  634.  
  635.     if {[lsearch -glob [set pgp($v,privatekeys)] "[lindex $key 0]*"] < 0} {
  636.         return {}
  637.     }
  638.  
  639.     # Search the passphrase "cache". Need to set-timeout here in case
  640.     # the pass phrase was created via the seditpgp entry field.
  641.     # Because of DecryptExpects asymmetric passphrase storage
  642.     # we need to look for both mainkey and subkey separately
  643.     set keyid [lindex $key 0]
  644.     set subkeyid [lindex $key 2]
  645.     if {([info exists pgp($v,pass,$keyid)]) && \
  646.         ([string length $pgp($v,pass,$keyid)] > 0)} {
  647.     Pgp_SetPassTimeout $v $keyid
  648.     if {[string length $subkeyid] > 0} {
  649.         Pgp_SetPassTimeout $v $subkeyid
  650.     }
  651.         return [set pgp($v,pass,$keyid)]
  652.     } elseif {([string length $subkeyid] > 0) && \
  653.         ([info exists pgp($v,pass,$subkeyid)]) && \
  654.         ([string length $pgp($v,pass,$subkeyid)] > 0)} {
  655.     Pgp_SetPassTimeout $v $subkeyid
  656.         return [set pgp($v,pass,$subkeyid)]
  657.     }
  658.  
  659.     # Not in "cache" (or expired) go ask for it.
  660.     while 1 {
  661.     Exmh_Debug "Attempt to get passphrase for [lindex $key 0] [lindex $key 1] [lindex $key 4]"
  662.         if [catch {Pgp_Misc_GetPass $v "Enter [set pgp($v,fullName)] passphrase" \
  663.                                    "Passphrase for [lindex $key 0] [lindex $key 1] [lindex $key 4]"} password] {
  664.             return {}
  665.         } elseif {[string match $keyid SYM]} {
  666.             # SYMMETRIC ENCRYPTION
  667.             return $password
  668.         } elseif {[Pgp_Exec_CheckPassword $v $password $key]} {
  669.             if [set pgp(keeppass)] {
  670.                 set pgp($v,pass,$keyid) $password
  671.         Pgp_SetPassTimeout $v $keyid
  672.                 # Because of DecryptExpect we need to store passphrase
  673.                 # for mainkey and subkey
  674.                 if {[string length $subkeyid] > 0} {
  675.                     set pgp($v,pass,$subkeyid) $password
  676.             Pgp_SetPassTimeout $v $subkeyid
  677.                 }
  678.             }
  679.             return $password
  680.         }
  681.     }
  682. }
  683.  
  684. proc Pgp_SetPassTimeout {v keyid} {
  685.     global pgp
  686.  
  687.     if [info exists pgp(timeout,$keyid)] {
  688.     Exmh_Debug "Cancelling previous timeout for $keyid"
  689.     after cancel $pgp(timeout,$keyid)
  690.     unset pgp(timeout,$keyid)
  691.     }
  692.     Exmh_Debug "Setting timeout for $keyid ($v) in $pgp(passtimeout) minutes"
  693.     set pgp(timeout,$keyid) \
  694.         [after [expr $pgp(passtimeout) * 60 * 1000] \
  695.                [list Pgp_ClearPassword $v $keyid]]
  696. }
  697.  
  698. # wipe password away
  699. proc Pgp_ClearPassword { v {keyid {}} } {
  700.     global pgp
  701.  
  702.     if {[string length $keyid] == 0} {
  703.         foreach index [array names pgp $v,pass*] {
  704.         Exmh_Debug "Clearing pgp($index)"
  705.             set pgp($index) {}
  706.         }
  707.         set pgp($v,pass,) {}
  708.     } else {
  709.     catch {Exmh_Debug "Clearing only pgp($v,pass,$keyid)"}
  710.         catch {set pgp($v,pass,$keyid) {}}
  711.     }
  712. }
  713.  
  714. proc Pgp_Exec_GetKeys { v keyid file } {
  715.     global pgp
  716.  
  717.     Exmh_Debug "Pgp_Exec_GetKeys $v $keyid $file"
  718.  
  719.     set arglist [subst [set pgp($v,args_exportKey)]]
  720.     ldelete arglist {}
  721.     if [Pgp_Exec $v key $arglist msg] {
  722.         error $msg
  723.     } else {
  724.         Pgp_Exec_CheckSuccess $v $file $msg "key block for $keyid"
  725.     }
  726. }
  727.  
  728. # Shutdown Cleanup
  729. proc Pgp_CheckPoint {} {
  730.     foreach cmd { Pgp_Match_CheckPoint } {
  731.         if {[info command $cmd] != {}} {
  732.             if [catch {$cmd} err] {
  733.                 puts stderr "$cmd: $err"
  734.             }
  735.         }
  736.     }
  737. }
  738.  
  739.  
  740. ### Init ###
  741.  
  742. proc Pgp_Exec_Init {} {
  743.     global env pgp
  744.  
  745.     Pgp_SetPath
  746.  
  747.     # needed in pgpMatch
  748.     if {![info exists env(LOCALHOST)]} {
  749.         if [catch {exec uname -n} env(LOCALHOST)] {
  750.             set env(LOCALHOST) localhost
  751.         }
  752.     }
  753.  
  754.     foreach v $pgp(supportedversions) {
  755.         if {[set pgp($v,enabled)]} {
  756.             set pgp($v,pass,) {}
  757.             # Parse config file
  758.             if { [set pgp($v,parse_config)] } {
  759.                 Pgp_Exec_ParseConfigTxt $v [set pgp($v,configFile)]
  760.             }
  761.             if {![file exists [set pgp($v,secring)]]} {
  762.                 set pgp($v,secring) {}
  763.             }
  764.             set pgp($v,privatekeys) [Pgp_Exec_KeyList $v $pgp($v,ownPattern) Sec]
  765.             #
  766.             if [info exists pgp($v,config,myname)] {
  767.                 set myname [string tolower [set pgp($v,config,myname)]]
  768.                 foreach key [set pgp($v,privatekeys)] {
  769.                     if {[string first $myname [string tolower $key]] >= 0} {
  770.             # pgp($v,myname) holds the default key to use
  771.             # for each version of PGP.  It will be used
  772.             # to initialize pgp($v,myname,$id) in each
  773.             # sedit window.
  774.                         set pgp($v,myname) $key
  775.                         break
  776.                     }
  777.                 }
  778.                 if {![info exists pgp($v,myname)]} {
  779.                     if [catch {Pgp_Match_Simple $v [set pgp($v,config,myname)] Sec} key] {
  780.                         tk_messageBox -type ok -icon warning \
  781.                                       -title "[set pgp($v,fullName)] Init" \
  782.                                       -message "The name specified in your [set pgp($v,fullName)] config file couldn't be unambiguously found in your key rings !"
  783.                         set pgp($v,myname) {}
  784.                     } else {
  785.                         set pgp($v,myname) $key
  786.                     }
  787.                 }
  788.             } else {
  789.                 set pgp($v,myname) [lindex [set pgp($v,privatekeys)] 0]
  790.             }
  791.         }
  792.     }
  793. }
  794.